home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
gnu
/
gas
/
src138.zoo
/
write.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-07-26
|
39KB
|
1,262 lines
/* write.c - emit .o file - Copyright(C)1986 Free Software Foundation, Inc.
Copyright (C) 1986,1987 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GAS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GAS; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/*
Umm, with real good luck, this thing should be set up to do byteordering
correctly, but I may have managed to miss a place or two. Treat a.out
very carefully until you're SURE that it works. . .
In order to cross-assemble the target machine must have an a.out header
similar to the one in a.out.h on THIS machine. Byteorder doesn't matter;
we take special care of it, but the numbers must be the same SIZE (# of
bytes) and in the same PLACE. If this is not true, you will have some
trouble.
*/
#include "as.h"
#include "md.h"
#include "subsegs.h"
#include "obstack.h"
#include "struc-symbol.h"
#include "write.h"
#include "symbols.h"
#ifdef SPARC
#include "sparc.h"
#endif
#ifdef I860
#include "i860.h"
#endif
void append();
#ifndef CROSSHPUX
#ifdef hpux
#define EXEC_MACHINE_TYPE HP9000S200_ID
#endif
#endif
#ifdef DOT_LABEL_PREFIX
#define LOCAL_LABEL(name) (name[0] =='.' \
&& ( name [1] == 'L' || name [1] == '.' ))
#else /* not defined DOT_LABEL_PREFIX */
#define LOCAL_LABEL(name) (name [0] == 'L' )
#endif /* not defined DOT_LABEL_PREFIX */
/*
* In: length of relocation (or of address) in chars: 1, 2 or 4.
* Out: GNU LD relocation length code: 0, 1, or 2.
*/
static unsigned char
nbytes_r_length [] = {
42, 0, 1, 42, 2
};
static struct frag * text_frag_root;
static struct frag * data_frag_root;
static struct frag * text_last_frag; /* Last frag in segment. */
static struct frag * data_last_frag; /* Last frag in segment. */
static struct exec the_exec;
static long int string_byte_count;
static char * the_object_file;
#if !defined(SPARC) && !defined(I860)
static
#endif
char * next_object_file_charP; /* Tracks object file bytes. */
static long int size_of_the_object_file; /* # bytes in object file. */
/* static long int length; JF unused */ /* String length, including trailing '\0'. */
static void relax_segment();
void emit_segment();
static relax_addressT relax_align();
static long int fixup_segment();
#if !defined(SPARC) && !defined(I860)
static void emit_relocations();
#endif
/*
* fix_new()
*
* Create a fixS in obstack 'notes'.
*/
void
#if defined(SPARC) || defined(I860)
fix_new (frag, where, size, add_symbol, sub_symbol, offset, pcrel, r_type)
#else
fix_new (frag, where, size, add_symbol, sub_symbol, offset, pcrel)
#endif
fragS * frag; /* Which frag? */
int where; /* Where in that frag? */
short int size; /* 1, 2 or 4 usually. */
symbolS * add_symbol; /* X_add_symbol. */
symbolS * sub_symbol; /* X_subtract_symbol. */
long int offset; /* X_add_number. */
int pcrel; /* TRUE if PC-relative relocation. */
#if defined(SPARC) || defined(I860)
int r_type;
#endif
{
register fixS * fixP;
fixP = (fixS *)obstack_alloc(¬es,sizeof(fixS));
fixP -> fx_frag = frag;
fixP -> fx_where = where;
fixP -> fx_size = size;
fixP -> fx_addsy = add_symbol;
fixP -> fx_subsy = sub_symbol;
fixP -> fx_offset = offset;
fixP -> fx_pcrel = pcrel;
fixP -> fx_next = * seg_fix_rootP;
/* JF these 'cuz of the NS32K stuff */
fixP -> fx_im_disp = 0;
fixP -> fx_pcrel_adjust = 0;
fixP -> fx_bsr = 0;
fixP ->fx_bit_fixP = 0;
#if defined(SPARC) || defined(I860)
fixP->fx_r_type = r_type;
#endif
* seg_fix_rootP = fixP;
}
void
write_object_file()
{
register struct frchain * frchainP; /* Track along all frchains. */
register fragS * fragP; /* Track along all frags. */
register struct frchain * next_frchainP;
register fragS * * prev_fragPP;
register char * name;
register symbolS * symbolP;
register symbolS ** symbolPP;
/* register fixS * fixP; JF unused */
unsigned
text_siz,
data_siz,
syms_siz,
tr_siz,
dr_siz;
void output_file_create();
void output_file_append();
void output_file_close();
#ifdef DONTDEF
void gdb_emit();
void gdb_end();
#endif
extern long omagic; /* JF magic # to write out. Is different for
Suns and Vaxen and other boxes */
#ifdef VMS
/*
* Under VMS we try to be compatible with VAX-11 "C". Thus, we
* call a routine to check for the definition of the procedure
* "_main", and if so -- fix it up so that it can be program
* entry point.
*/
VMS_Check_For_Main();
#endif /* VMS */
/*
* After every sub-segment, we fake an ".align ...". This conforms to BSD4.2
* brane-damage. We then fake ".fill 0" because that is the kind of frag
* that requires least thought. ".align" frags like to have a following
* frag since that makes calculating their intended length trivial.
*/
#define SUB_SEGMENT_ALIGN (2)
for ( frchainP=frchain_root; frchainP; frchainP=frchainP->frch_next )
{
#ifdef VMS
/*
* Under VAX/VMS, the linker (and PSECT specifications)
* take care of correctly aligning the segments.
* Doing the alignment here (on initialized data) can
* mess up the calculation of global data PSECT sizes.
*/
#undef SUB_SEGMENT_ALIGN
#define SUB_SEGMENT_ALIGN ((frchainP->frch_seg != SEG_DATA) ? 2 : 0)
#endif /* VMS */
subseg_new (frchainP -> frch_seg, frchainP -> frch_subseg);
frag_align (SUB_SEGMENT_ALIGN, 0);
/* frag_align will have left a new frag. */
/* Use this last frag for an empty ".fill". */
/*
* For this segment ...
* Create a last frag. Do not leave a "being filled in frag".
*/
frag_wane (frag_now);
frag_now -> fr_fix = 0;
know( frag_now -> fr_next == NULL );
/* know( frags . obstack_c_base == frags . obstack_c_next_free ); */
/* Above shows we haven't left a half-completed object on obstack. */
}
/*
* From now on, we don't care about sub-segments.
* Build one frag chain for each segment. Linked thru fr_next.
* We know that there is at least 1 text frchain & at least 1 data frchain.
*/
prev_fragPP = &text_frag_root;
for ( frchainP=frchain_root; frchainP; frchainP=next_frchainP )
{
know( frchainP -> frch_root );
* prev_fragPP = frchainP -> frch_root;
prev_fragPP = & frchainP -> frch_last -> fr_next;
if ( ((next_frchainP = frchainP->frch_next) == NULL)
|| next_frchainP == data0_frchainP)
{
prev_fragPP = & data_frag_root;
if ( next_frchainP )
{
text_last_frag = frchainP -> frch_last;
}
else
{
data_last_frag = frchainP -> frch_last;
}
}
} /* for(each struct frchain) */
/*
* We have two segments. If user gave -R flag, then we must put the
* data frags into the text segment. Do this before relaxing so
* we know to take advantage of -R and make shorter addresses.
*/
if ( flagseen [ 'R' ] )
{
fixS *tmp;
text_last_frag -> fr_next = data_frag_root;
text_last_frag = data_last_frag;
data_last_frag = NULL;
data_frag_root = NULL;
if(text_fix_root) {
for(tmp=text_fix_root;tmp->fx_next;tmp=tmp->fx_next)
;
tmp->fx_next=data_fix_root;
} else
text_fix_root=data_fix_root;
data_fix_root=NULL;
}
relax_segment (text_frag_root, SEG_TEXT);
relax_segment (data_frag_root, SEG_DATA);
/*
* Now the addresses of frags are correct within the segment.
*/
know( text_last_frag -> fr_type == rs_fill && text_last_frag -> fr_offset == 0 );
text_siz=text_last_frag->fr_address;
#ifdef SPARC
text_siz= (text_siz+7)&(~7);
te